use chrono::NaiveDateTime;

use crate::AppState;
use chat_core::{error::AppError, ChatUser, CreateWorkspace, User, Workspace};

#[allow(dead_code)]
impl AppState {
    pub async fn fetch_workspace_by_id(&self, id: u64) -> Result<Option<Workspace>, AppError> {
        let workspace: Option<Workspace> =
            sqlx::query_as(r#"SELECT * FROM workspaces WHERE id = $1"#)
                .bind(id as i64)
                .fetch_optional(&self.pool)
                .await?;
        Ok(workspace)
    }
    pub async fn fetch_workspace_by_name(&self, name: &str) -> Result<Option<Workspace>, AppError> {
        let workspace: Option<Workspace> =
            sqlx::query_as(r#"SELECT * FROM workspaces WHERE name = $1"#)
                .bind(name)
                .fetch_optional(&self.pool)
                .await?;
        Ok(workspace)
    }

    pub async fn fetch_all_chat_users_by_ws_id(&self, id: u64) -> Result<Vec<ChatUser>, AppError> {
        let users: Vec<ChatUser> = sqlx::query_as(
            r#" SELECT
           id,fullname,email
         from users
        WHERE ws_id = $1
      "#,
        )
        .bind(id as i64)
        .fetch_all(&self.pool)
        .await?;
        Ok(users)
    }

    pub async fn del_ws_by_name(&self, name: &str) -> Result<(), AppError> {
        sqlx::query(r#"DELETE FROM workspaces WHERE name = $1"#)
            .bind(name)
            .execute(&self.pool)
            .await?;
        Ok(())
    }

    pub async fn update_ws_owner_by_id(
        &self,
        ws_id: i64,
        user_id: i64,
        user_name: &str,
    ) -> Result<(), AppError> {
        if ws_id == 0 {
            sqlx::query(
                r#"UPDATE workspaces
                SET owner_id = $1 ,
                created_name = $2,
                updated_name = $3
               WHERE id = $4"#,
            )
            .bind(user_id)
            .bind(user_name)
            .bind(user_name)
            .bind(ws_id)
            .execute(&self.pool)
            .await?;
        }
        Ok(())
    }
    pub async fn create_ws(&self, ws_name: &str) -> Result<Workspace, AppError> {
        let now = NaiveDateTime::default();
        let ws_opt = self.fetch_workspace_by_name(ws_name).await?;
        let Some(ws) = ws_opt else {
            let ws = sqlx::query_as(
                r#" INSERT INTO workspaces (
                 owner_id,
                  name,
                  created_date,
                  created_name
                  ) VALUES ($1, $2, $3, $4)
                  returning id, name, owner_id, created_date, created_name, updated_date, updated_name
      "#,
            )
            .bind(0)
            .bind(ws_name)
            .bind(now)
            .bind("SYSTEM")
            .fetch_one(&self.pool)
            .await?;
            return Ok(ws);
        };
        Ok(ws)
    }

    // 创建工作空间

    pub async fn create_workspace(
        &self,
        create_workspace: &CreateWorkspace,
        user: &User,
    ) -> Result<Option<Workspace>, AppError> {
        // 判断工作空间是否存在
        let ws_opt: Option<Workspace> =
            sqlx::query_as(r#"SELECT * FROM workspaces WHERE name = $1"#)
                .bind(&create_workspace.name)
                .fetch_optional(&self.pool)
                .await?;
        let Some(ws) = ws_opt else {
            // 创建一个工作空间
            let now = NaiveDateTime::default();
            let ws: Workspace = sqlx::query_as(
                r#"INSERT INTO workspaces (
            name,
            owner_id,
            created_date,
            created_name,
            updated_date,
            updated_name
            ) VALUES ($1, $2, $3, $4, $5, $6)
            returning id, name, owner_id, created_date, created_name, updated_date, updated_name
            "#,
            )
            .bind(&create_workspace.name)
            .bind(user.id)
            .bind(now)
            .bind(&user.fullname)
            .bind(now)
            .bind(&user.fullname)
            .fetch_one(&self.pool)
            .await?;
            return Ok(Some(ws));
        };
        Ok(Some(ws))
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    use anyhow::Result;
    use chat_core::CreateUser;
    use jwt_simple::reexports::rand::{self, Rng as _};

    #[tokio::test]
    async fn test_create_workspace() -> Result<(), AppError> {
        let mut range = rand::thread_rng();
        let rang_num: u8 = range.gen();
        let fullname = "jinyulinlang".to_string();
        let email = format!("jinyulinlang{0}@qq.com", rang_num);
        let ws_id = 0;
        let password = "123456".to_string();
        let create_user = CreateUser::new(fullname, email.clone(), ws_id, password);
        let state = AppState::new_for_test().await?;
        let user = state.create_user(&create_user).await?;
        let ws_name = format!("jinyulinlang{0}", rang_num);
        let create_workspace = CreateWorkspace::new(ws_name.clone());
        let ws_opt = state.create_workspace(&create_workspace, &user).await?;
        println!("{:?}", ws_opt);
        assert!(ws_opt.is_some());
        match ws_opt {
            Some(ws) => {
                let ws_id = state
                    .update_user_ws_id_by_user_id(user.id, ws.id, user.fullname.clone())
                    .await?;
                assert_eq!(ws.name, create_workspace.name.clone());
                assert_eq!(ws.owner_id, user.id);
                assert_eq!(ws.id, ws_id);
            }
            None => {
                panic!("创建工作空间失败");
            }
        }
        state.delete_user_by_email(&email).await?;
        state.del_ws_by_name(&ws_name).await?;
        Ok(())
    }

    #[tokio::test]
    async fn test_fetch_all_chat_users() -> Result<(), AppError> {
        let mut range = rand::thread_rng();
        let rang_num: u8 = range.gen();
        let fullname = "jinyulinlang".to_string();
        let email = format!("jinyulinlang{0}@qq.com", rang_num);
        let ws_id = 1;
        let password = "123456".to_string();
        let create_user = CreateUser::new(fullname, email.clone(), ws_id, password);
        let state = AppState::new_for_test().await?;
        let user: User = state.create_user(&create_user).await?;
        let users = state
            .fetch_all_chat_users_by_ws_id(user.ws_id as u64)
            .await?;
        assert!(!users.is_empty());
        state.delete_user_by_email(&email).await?;
        Ok(())
    }
    #[tokio::test]
    async fn test_fetch_ws_by_name_or_by_id() -> Result<(), AppError> {
        let mut range = rand::thread_rng();
        let rang_num: u8 = range.gen();
        let fullname = "jinyulinlang".to_string();
        let email = format!("jinyulinlang{0}@qq.com", rang_num);
        let ws_id = 1;
        let password = "123456".to_string();
        let create_user = CreateUser::new(fullname, email.clone(), ws_id, password);
        let state = AppState::new_for_test().await?;
        let user: User = state.create_user(&create_user).await?;
        let ws_name = format!("jinyulinlang{0}", rang_num);
        let create_workspace = CreateWorkspace::new(ws_name.clone());
        let ws_opt = state.create_workspace(&create_workspace, &user).await?;
        assert!(ws_opt.is_some());
        let Some(ws) = state.fetch_workspace_by_name(&ws_name).await? else {
            panic!(" fetch_by_name error: {}", &ws_name);
        };
        let Some(ws) = state.fetch_workspace_by_id(ws.id as u64).await? else {
            panic!("fetch_by_id error: {}", ws.id);
        };
        assert_eq!(ws.name, ws_name.clone());
        state.delete_user_by_email(&email).await?;
        state.del_ws_by_name(&ws_name).await?;
        Ok(())
    }
    #[tokio::test]
    async fn test_create_ws_with_name() -> Result<(), AppError> {
        let mut range = rand::thread_rng();
        let rang_num: u8 = range.gen();
        let state = AppState::new_for_test().await?;
        let ws_name = format!("jinyulinlang{0}", rang_num);
        let ws = state.create_ws(&ws_name).await?;
        assert_eq!(ws.name, ws_name.clone());
        state.del_ws_by_name(&ws_name).await?;
        Ok(())
    }
}
